#ifndef _GWBASE_BASE_FILE_OPS_H_
#define _GWBASE_BASE_FILE_OPS_H_

#include <sys/stat.h>
#include <sys/vfs.h>
#include <stdio.h>
#include <dirent.h>
#include <string>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include "gwbase/base/slice.h"
#include "gwbase/base/timestamp.h"
#include "gwbase/base/status.h"

namespace dicom {

struct FileInfo {
  enum FileType {
    kRegular = 0,
    kDirectory,
    kSymLink,
    kBlock,
    kChar,
    kNotExists,
    kError,
  };

  FileType type;
  size_t size;
  mode_t mode;
  Timestamp mtime;

  bool is_regular() const { return type == kRegular; }
  bool is_dir() const { return type == kDirectory; }
  bool is_dev() const { return type == kBlock || type == kChar; }
  bool not_exists() const { return type == kNotExists; }
};

class WritableFile;
class SequentialFile;

typedef boost::shared_ptr<WritableFile> WritableFilePtr;
typedef boost::shared_ptr<SequentialFile> SequentialFilePtr;

// A file abstraction for sequential writing
class WritableFile : public boost::noncopyable {
 public:
  static Status Open(const std::string& path, bool truncate,
                     WritableFilePtr* file);

  virtual ~WritableFile();

  Status Append(const Slice& data);
  Status Append(const void* data, size_t n);
  Status Sync();
  Status Flush();
  Status Close();
  Status SetMtime(const Timestamp& mtime);

 private:
  WritableFile(FILE* f) : f_(f) {}

  FILE* f_;
};

// A file abstraction for reading sequentially through a file
class SequentialFile {
 public:
  static Status Open(const std::string& path, SequentialFilePtr* file);
  ~SequentialFile();

  Status Read(void* buf, size_t len, size_t* read_len);
  Status SeekTo(off_t pos);

 private:
  SequentialFile(FILE* f) : f_(f) {}
  FILE* f_;
};

// Read all content of a file to std::string, you should
// use this only for small configuration files
extern Status ReadSmallFile(const std::string& path, std::string* content);

// Write to string to file, if failed, it will delete that file
extern Status WriteStringToFile(const std::string& path,
                                const std::string& data);

extern Status FileExists(const std::string& path, bool* exists);
extern Status DeleteFile(const std::string& path);
extern Status RenameFile(const std::string& src, const std::string& target);

extern Status CreateDir(const std::string& path);
extern Status CreateDirRecurisve(const std::string& path);
extern Status DeleteDir(const std::string& path);

extern Status StatPath(const std::string& path, FileInfo* out);
extern Status GetFileSize(const std::string& path, size_t* size);

extern Status SetFileMtime(const std::string& path, Timestamp mtime);

extern Status Statfs(const std::string& path, struct statfs64* buf);

typedef std::vector<struct dirent*> DirentList;
extern Status ScanDir(const std::string& path, DirentList* list);
extern void FreeDirentList(DirentList* list);
}

#endif  // _GWBASE_BASE_FILE_OPS_H_
